﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Minestorm.Retro.GameLogic;

namespace Minestorm.Retro.Entities
{
    public enum MineSize
    {
        Small = 2,
        Medium = 1,
        Large = 0
    }

    public abstract class Mine : Entity
    {
        private GraphicsDevice _graphics;
        public int _children = 0;
        public int _maxChildren = 2;

        public bool HasFireball { get; set; }

        public float Angle { get; set; }

        public bool IsMagnetic { get; set; }

        public float Speed { get; set; }

        public bool AutoSpawned { get; set; }

        public static TimeSpan SpawnDelay = TimeSpan.FromMilliseconds(300);

        public Mine(GraphicsDevice graphics, MineSize mineSize, Vector2 position)
            : base(graphics, position)
        {
            MineSize = mineSize;
            _graphics = graphics;
            HasFireball = false;
            IsMagnetic = false;
        }

        public bool CanSpawnChild()
        {
            return _children < _maxChildren;
        }

        public MineType MineType { get; protected set; }

        protected abstract int ShellLineCount { get; }

        public Boolean CheckPointCollision(Vector3[] points, out int vectorIndex)
        {
            return CollisionHelper.CheckPointCollision(points, GetWorld("mine"), ShellLineCount, Verticies, out vectorIndex);
        }

        public Boolean CheckLineCollision(Vector2 ls, Vector2 le)
        {
            return CollisionHelper.CheckLineCollision(ls, le, GetWorld("mine"), ShellLineCount, Verticies);
        }

        public override Matrix GetWorld(string indexBufferName)
        {
            Matrix worldMatrix = Matrix.Identity;

            if (indexBufferName == "mine")
                for (var i = 0; i <= (int)MineSize; i++)
                    worldMatrix *= Matrix.CreateScale(.5f);

            return worldMatrix * Matrix.CreateTranslation(new Vector3(Position, 0f));
        }

        public MineSize MineSize { get; set; }

        public override void Initialize()
        {
            InitializeVectors();
        }

        protected abstract void InitializeVectors();

        public bool ShouldMove(GameTime gameTime)
        {
            return gameTime.TotalGameTime - BornOn > SpawnDelay;
        }

        public virtual void Move(Vector2? shipPosition)
        {
            if (IsMagnetic && shipPosition != null)
            {
                var ship = shipPosition.Value;
                var mine = Position;
                var newX = mine.X;
                var newY = mine.Y;

                var distX1 = (float)(ship.X - mine.X);
                var distX2 = (float)(ship.X - (mine.X + Constants.Level.MaxX * 2));
                var distX3 = (float)((ship.X + Constants.Level.MaxX * 2) - mine.X);
                var distY1 = (float)(ship.Y - mine.Y);
                var distY2 = (float)(ship.Y - (mine.Y + Constants.Level.MaxY * 2));
                var distY3 = (float)((ship.Y + Constants.Level.MaxY * 2) - mine.Y);

                var tx = Math.Abs(distX1) < Math.Abs(distX2) ? distX1 : distX2;
                tx = Math.Abs(tx) < Math.Abs(distX3) ? tx : distX3;

                var ty = Math.Abs(distY1) < Math.Abs(distY2) ? distY1 : distY2;
                ty = Math.Abs(ty) < Math.Abs(distY3) ? ty : distY3;

                var length = (float)Math.Sqrt(tx * tx + ty * ty);

                if (length > Speed)
                    Position = new Vector2(Position.X + Speed * tx / length, Position.Y + Speed * ty / length);
                else
                    Position = new Vector2(shipPosition.Value.X, shipPosition.Value.Y);
            }
            else
            {
                Position = new Vector2(Position.X + (float)Math.Sin(-Angle) * Speed, Position.Y + (float)Math.Cos(-Angle) * Speed);
            }

            Position = WrapBounds(Position);
        }
    }
}
